
package com.apexsoft.assets.base.utils;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;


/**
 * Java类型转换工具类
 *
 */
public class JavaTypes {

	private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<String, Class<?>>(32);
	private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new HashMap<Class<?>, Class<?>>(8);
	static{
		primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
		primitiveWrapperTypeMap.put(Byte.class, byte.class);
		primitiveWrapperTypeMap.put(Character.class, char.class);
		primitiveWrapperTypeMap.put(Double.class, double.class);
		primitiveWrapperTypeMap.put(Float.class, float.class);
		primitiveWrapperTypeMap.put(Integer.class, int.class);
		primitiveWrapperTypeMap.put(Long.class, long.class);
		primitiveWrapperTypeMap.put(Short.class, short.class);

		
		Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(32);
		primitiveTypes.addAll(primitiveWrapperTypeMap.values());
		primitiveTypes.addAll(Arrays.asList(new Class<?>[] {
				boolean[].class, byte[].class, char[].class, double[].class,
				float[].class, int[].class, long[].class, short[].class}));
		primitiveTypes.add(void.class);
		for (Class<?> primitiveType : primitiveTypes) {
			primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
		}
	}
	
    public static final int BOOLEAN = 0;
    public static final int BYTE = 1;
    public static final int CHAR = 2;
    public static final int DOUBLE = 3;
    public static final int FLOAT = 4;
    public static final int INT = 5;
    public static final int LONG = 6;
    public static final int SHORT = 7;
    public static final int OBJECT = 8;
    public static final int STRING = 9;
    public static final int NUMBER = 10;
    public static final int DATE = 11;
    public static final int BOOLEAN_OBJ = 12;
    public static final int BYTE_OBJ = 13;
    public static final int CHAR_OBJ = 14;
    public static final int DOUBLE_OBJ = 15;
    public static final int FLOAT_OBJ = 16;
    public static final int INT_OBJ = 17;
    public static final int LONG_OBJ = 18;
    public static final int SHORT_OBJ = 19;
    public static final int BIGDECIMAL = 20;
    public static final int BIGINTEGER = 21;
    public static final int CALENDAR = 22;
   //public static final int LOCALE = 23;
   // public static final int ENUM = 24;


    private static final Map<Class<?>, Integer> _typeCodes = new HashMap<Class<?>, Integer>();

    static {
        _typeCodes.put(String.class, STRING);
        _typeCodes.put(Boolean.class, BOOLEAN_OBJ);
        _typeCodes.put(Byte.class, BYTE_OBJ);
        _typeCodes.put(Character.class, CHAR_OBJ);
        _typeCodes.put(Double.class, DOUBLE_OBJ);
        _typeCodes.put(Float.class, FLOAT_OBJ);
        _typeCodes.put(Integer.class, INT_OBJ);
        _typeCodes.put(Long.class, LONG_OBJ);
        _typeCodes.put(Short.class, SHORT_OBJ);
        _typeCodes.put(Date.class, DATE);
        _typeCodes.put(java.sql.Date.class, DATE);
        _typeCodes.put(java.sql.Timestamp.class, DATE);
        _typeCodes.put(java.sql.Time.class, DATE);
        _typeCodes.put(BigInteger.class, BIGINTEGER);
        _typeCodes.put(BigDecimal.class, BIGDECIMAL);
        _typeCodes.put(Number.class, NUMBER);
       // _typeCodes.put(Locale.class, LOCALE);
        _typeCodes.put(Object.class, OBJECT);
        _typeCodes.put(Calendar.class, CALENDAR);
    }

    /**
     * Return the field metadata type code for the given class. First class
     * objects are not recognized in this method.
     */
    public static int getTypeCode(Class<?> type) {
        if (type == null)
            return OBJECT;

        if (type.isPrimitive()) {
            switch (type.getName().charAt(0)) {
                case 'b':
                    return (type == boolean.class) ? BOOLEAN : BYTE;
                case 'c':
                    return CHAR;
                case 'd':
                    return DOUBLE;
                case 'f':
                    return FLOAT;
                case 'i':
                    return INT;
                case 'l':
                    return LONG;
                case 's':
                    return SHORT;
            }
        }

        Integer code = (Integer) _typeCodes.get(type);
        if (code != null)
            return code.intValue();

       
        if (Calendar.class.isAssignableFrom(type))
            return CALENDAR;

        if (type.isInterface()) {
            if (Serializable.class.isAssignableFrom(type))
                return OBJECT;
        }
//        if (type.isAssignableFrom(Reader.class))
//            return INPUT_READER;
//        if (type.isAssignableFrom (InputStream.class))
//            return INPUT_STREAM;
//        if (Enum.class.isAssignableFrom(type))
//            return ENUM;
            
        return OBJECT;
    }
 


    /**
     * Helper method to return the given array value as a collection.
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> toList(Object val, Class<T> elem, boolean mutable) {
        if (val == null)
            return null;

        List<T> l;
        if (!elem.isPrimitive()) {
            // if an object array, use built-in list function
            l = Arrays.asList((T[]) val);
            if (mutable)
                l = new ArrayList<T>(l);
        } else {
            // convert to list of wrapper objects
            int length = Array.getLength(val);
            l = new ArrayList<T>(length);
            for (int i = 0; i < length; i++)
                l.add((T)Array.get(val, i));
        }
        return l;
    }

    /**
     * Helper method to return the given collection as an array.
     */
    public static Object toArray(Collection<?> coll, Class<?> elem) {
        if (coll == null)
            return null;

        Object array = Array.newInstance(elem, coll.size());
        int idx = 0;
        for (Iterator<?> itr = coll.iterator(); itr.hasNext(); idx++)
            Array.set(array, idx, itr.next ());
		return array;
	}
    
    /**
     * Determine whether or not the provided Object value is the default for the provided typeCode.
     * 
     * For example: If o = Integer(0) and typeCode = JavaTypes.INT, this method will return true.
     */
    public static boolean isPrimitiveDefault(Object o, int typeCode) {
        switch (typeCode) {
            case BOOLEAN:
                return ((Boolean) o).equals(Boolean.FALSE) ? true : false;
            case BYTE:
                return ((Byte) o) == 0 ? true : false;
            case SHORT:
                return ((Short) o) == 0 ? true : false;
            case INT:
                return ((Integer) o) == 0 ? true : false;
            case LONG:
                return ((Long) o) == 0L ? true : false;
            case FLOAT:
                return ((Float) o) == 0.0F ? true : false;
            case CHAR:
                return ((Character) o) == '\u0000' ? true : false;
            case DOUBLE:
                return ((Double) o) == 0.0d ? true : false;
        }
        return false;
    }
    
	public static Class<?> resolvePrimitiveClassName(String name) {
		Class<?> result = null;
		if (name != null && name.length() <= 8) {
			// Could be a primitive - likely.
			result = primitiveTypeNameMap.get(name);
		}
		return result;
	}
}
